package com.xnx3.kefu.core.socket;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.xnx3.BaseVO;
import com.xnx3.j2ee.bean.ActiveUser;
import com.xnx3.j2ee.util.ConsoleUtil;
import com.xnx3.kefu.core.Global;
import com.xnx3.kefu.core.bean.ChatUserBean;
import com.xnx3.kefu.core.pluginManage.interfaces.manage.MessagePluginManage;
import com.xnx3.kefu.core.util.MessageStorageUtil;
import com.xnx3.kefu.core.util.MessageUtil;
import com.xnx3.kefu.core.util.OfflineMessageUtil;
import com.xnx3.kefu.core.util.SessionUtil;
import com.xnx3.kefu.core.util.SocketUtil;
import com.xnx3.kefu.core.util.TokenUtil;
import com.xnx3.kefu.core.util.UserUtil;
import com.xnx3.kefu.core.vo.MessageReceiveVO;
import com.xnx3.kefu.core.vo.bean.MessageTypeEnum;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;

/**
 * 自定义助手类
 * @author 管雷鸣
 *
 */
public class NettyHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {//TextWebSocketFrame是netty用于处理websocket发来的文本对象
	//所有正在连接的channel都会存在这里面，所以也可以间接代表在线的客户端
	public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
	// key  Channel.id ， 
	public static Map<String, Channel> channelMap;
	static{
		channelMap = new HashMap<String, Channel>();
	}
	

	/**
     * 客户端创建的时候触发，当客户端连接上服务端之后，就可以获取该channel，然后放到channelGroup中进行统一管理	
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        channelGroup.add(ctx.channel());
        MessagePluginManage.online(ctx.channel());
    }
    
    /**
     * 关闭连接,客户端销毁的时候触发
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
    	MessagePluginManage.offline(ctx.channel());
    	SocketUtil.unbind(ctx.channel());
    	channelGroup.remove(ctx.channel());
    }

    //出现异常
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
    }
    
    
    /**
     * 接收到客户端发来的消息进行处理
     */
	@Override
	protected void messageReceived(ChannelHandlerContext ctx, TextWebSocketFrame textWebSocketFrame) throws Exception {
		//客户端传递过来的消息
		String content = textWebSocketFrame.text();
		MessageReceiveVO msg = MessageUtil.receive(content);
		
		if(msg.getType().equalsIgnoreCase(MessageTypeEnum.HEARTBEAT.name)){
			//心跳，回应
			SocketUtil.sendHeartbeatMessageReply(ctx.channel());
			return;
		}
		
		MessageStorageUtil.push(msg); //消息进行持久化存储
//		ConsoleUtil.log("messageReceived: "+content);
		
		//判断此条是否是刚打开连接成功自动发送的。如果是，那么进行绑定通道跟用户
		if(msg.getType().equalsIgnoreCase(MessageTypeEnum.CONNECT.name)){
			//open时推送来的消息
			
			//判断用户是否存在，绑定了token
//			User user = TokenBind.bind(receive.getToken(), user);
//			ChatUserBean chatUser = TokenUtil.getUser(msg.getToken());
			String chatid = TokenUtil.getChatid(msg.getToken());
			ChatUserBean chatUser = null;	//下面的if中赋予
//			ConsoleUtil.log("NettyHandler token:"+msg.getToken()+", user:"+chatUser);
			if(chatid == null){
				//未绑定过token，那么新绑定它
				
				//判断它是否是游客
				if(msg.getToken().indexOf("youke_") != 0){
					//不是游客，那么判断一下这个sessionid是否有效，有没有对应的用户信息
					ActiveUser activeUser = SessionUtil.getActiveUser(msg.getToken());
					if(activeUser == null || activeUser.getUser() == null){
						if(Global.imMustLogin){
							//必须登录的
							SocketUtil.sendSystemMessage(msg.getSendId(), msg.getReceiveId(), "您尚未登录，请先登录");
							return;
						}
					}else{
						chatUser = new ChatUserBean();
						chatUser.setUser(activeUser.getUser());
						chatid = chatUser.getChatid();
					}
				}
				
				if(chatid == null){
					//未登录，创建游客身份。这一步应该在刚打开im时就通过接口创建过了。可能中间服务器重启会导致丢失，才会到这里
					chatUser = TokenUtil.generateYoukeUser(msg.getToken());
					ConsoleUtil.info("socket open, 创建游客user："+chatUser.toString());
				}
			}else{
				//chatid 有值，那就直接从 UserUtil中取
				chatUser = UserUtil.getUser(chatid);
			}
			
			SocketUtil.bind(chatUser, ctx.channel());		//user跟socket通道绑定
			UserUtil.bind(chatUser); 	//userid 跟 user 绑定。主要游客会有作用。根据id获取游客的user
			TokenUtil.bind(msg.getToken(), chatUser);	//token跟user绑定
			
//			ConsoleUtil.info("socket open, token："+msg.getToken()+", channel:"+ctx.channel().localAddress());
			//设置客户端用户的信息
			//SocketUtil.sendSetUserMessage(ctx.channel(), user);
			
			//将该用户的离线消息给他推送过去
			if(chatUser != null){
				OfflineMessageUtil.sendOfflineMessage(chatUser.getChatid(), ctx.channel());
			}
			
			/*** 响应链接成功 ***/
//			msg.setResult(BaseVO.FAILURE);
//			msg.setInfo("success");
//			SocketUtil.sendMessage(ctx.channel(), msg);	
			return;
		}
		
		//拉取对方的自动回复
		if(msg.getType().equalsIgnoreCase(MessageTypeEnum.AUTO_REPLY.name)){
			MessagePluginManage.autoReply(ctx.channel(), msg.getReceiveId());
			
			String text = MessageUtil.autoReply(msg.getReceiveId());
			if(text != null){
				//响应顾客，设定的客服自动回复的内容
				msg.setText(text);
				String cont = MessageUtil.send(msg.getType(), msg.getReceiveId(), msg.getSendId(), text, null);
				SocketUtil.sendMessage(ctx.channel(), cont);
			}
			return;
		}
		
		boolean messageReceivedChatResult = MessagePluginManage.messageReceivedChat(ctx.channel(), msg);
		if(!messageReceivedChatResult){
			//终止后面的执行
			return;
		}
		
		
		//正常发送的消息，文字、表情等消息，那么判断一下是否是在常见问题中匹配，如果常见问题中的，那么直接自动回复
		if(msg.getType().equalsIgnoreCase(MessageTypeEnum.MSG.name)){
			String text = MessageUtil.autoReplyQuestion(msg.getReceiveId(), msg.getText());
			if(text != null){
				//匹配上自动回复问题了，那么直接自动回复给用户，先不用再发送给接受者
				
				String msgText = MessageUtil.send(MessageTypeEnum.MSG.name, msg.getReceiveId(), msg.getSendId(), text, null);
				SocketUtil.sendMessage(ctx.channel(), msgText);
				//ConsoleUtil.log("自动回复问题    "+msg.getText()+":"+text);
				return;
			}
		}
		
		//正常沟通推送过来的消息、扩展消息，进行对话
		if(msg.getType().equalsIgnoreCase(MessageTypeEnum.MSG.name) || msg.getType().equalsIgnoreCase(MessageTypeEnum.EXTEND.name)){
			//首先判断是否是自己发给自己的，如果是，那么不允许自己发给自己
			if(msg.getSendId().equalsIgnoreCase(msg.getReceiveId())){
				SocketUtil.sendSystemMessage(msg.getSendId(), msg.getReceiveId(), "您不能自己给自己发消息。注意，此种情况基本都是在测试时会遇到，在同一浏览器中同时登录了坐席后台跟访客客服咨询的窗口。因为本客服系统大量使用了本地缓存来提高流畅优化体验，所以如果你同时打开坐席窗口跟访客咨询窗口，会使缓存冲突，导致出现这种情况。[br]解决方式：坐席后台、访客咨询， 用两个不同的浏览器来测试即可。");
				return;
			}
			
			//将消息发送到对方那里。客户端是直接传的本地token的，也就是 msg.getToken() 只是发送方的token， 将发送方的token转为 chatid
//			ChatUserBean sendChatUser = TokenUtil.getUser(msg.getToken());
			String sendChatid = TokenUtil.getChatid(msg.getToken());
			if(sendChatid == null){
				ConsoleUtil.error("TokenUtil.getChatid(token) ，根据token没发现用户！token:"+msg.getSendId());
				return;
			}
			msg.setSendId(sendChatid);
			
			String cont = MessageUtil.send(msg);
			List<Channel> channelList = SocketUtil.getChannel(msg.getReceiveId());
			if(channelList == null || channelList.size() == 0){
				//对方已经离线了
				MessagePluginManage.offlineMessage(ctx.channel(), msg);
				//持久化记录离线消息
				OfflineMessageUtil.addOfflineMessage(msg);
				//SocketUtil.sendSystemMessage(ctx.channel(), msg.getReceiveId(), "对方已离线");
			}else{
				//对方在线，给对方推送过去
				SocketUtil.sendMessage(channelList, cont);
			}
			return;
		}
		
	
	}
}